﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;

using SypConst.Garbage;
using System.Collections;
using System.IO;
using System.Net.Sockets;
using SuperSocket.SocketBase.Command;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketBase.Logging;
using SuperWebSocket;
using SuperSocket.SocketBase.Config;
using System.Configuration;
using SuperSocket.SocketBase.Provider;
using SuperSocket.SocketBase;
using Newtonsoft.Json.Linq;
using System.Resources;

using Newtonsoft.Json;
using SypEngine;

namespace SypServer
{
    public sealed class JsonMsgStatus
    {
        public const string INFO = "info";
        public const string ALERT = "alert";
        public const string SUCCESS = "success";
        public const string ERROR = "error";
    }

    public class JsonResponse
    {
        private int siteId = -1;
        private string jsonString = string.Empty;
        private JObject jsonData = null;

        public static JsonResponse GetJsonResponse(int siteID, string action, object[] parameters)
        {
            string content = "{}";
            switch (action)
            {
                case "tick":
                    content = "{\"action\" : \"tick\", \"timer\" : \"" + parameters[0] + "\" }";
                    break;
                case "localStep":
                    content = "{\"action\" : \"localStep\", \"step\" : \"" + parameters[0] + "\", \"total\" : \"" + parameters[1] + "\" }";
                    break;
                case "updateDone":
                    content = "{\"action\" : \"updateDone\" }";
                    break;
                case "deleteDone":
                    content = "{\"action\" : \"deleteDone\" }";
                    break;
                case "onlineStep":
                    content = "{\"action\" : \"onlineStep\", \"step\" : \"" + parameters[0] + "\", \"total\" : \"" + parameters[1] + "\" }";
                    break;
                case "onlineDone":
                    content = "{\"action\" : \"onlineDone\" }";
                    break;
                case "browseFolder":
                    content = "{\"action\" : \"browseFolder\", \"path\" : \"" + parameters[0] + "\" }";
                    break;
                case "browseFile":
                    content = "{\"action\" : \"browseFile\", \"path\" : \"" + parameters[0] + "\" }";
                    break;
                case "msg":
                    content = "{\"action\" : \"msg\", \"status\" : \"" + parameters[0] + "\", \"title\" : \"" + parameters[1] + "\",\"msg\" : \"" + parameters[2] + "\" }";
                    break;
                case "checkSynchronized":
                    content = "{\"action\" : \"checkSynchronized\", \"list\" : " + JsonConvert.SerializeObject(parameters[0]) + " }";
                    break;
                case "checkSynchronizedFlag":
                    content = "{\"action\" : \"checkSynchronizedFlag\", \"id\" : \"" + parameters[0] + "\" }";
                    break;
            }
            return new JsonResponse(siteID, content);
        }


        private JsonResponse(int siteId, string content)
        {
            this.siteId = siteId;
            this.jsonString = content;
            this.jsonData = JObject.Parse(content);
        }

        public int SiteID
        {
            get { return this.siteId;  }
        }

        public JObject JsonObject
        {
            get { return jsonData; }
        }

        public string JsonStringified
        {
            get { return jsonString; }
        }
    }

    public class SypWebsocketSuperPoolServer
    {
        private const int autoRestartLoop = 5;
        private Hashtable ConnectionPools = null;
        private WebSocketServer  SypWebSocketServer = null;
        private SetText _Output = null;
        public event VisitorCallBack onFirstConnection = null;

        private WebSocketSession GetWebSocketSession(int SiteId)
        {
            
            if (ConnectionPools.ContainsKey(SiteId))
                return (WebSocketSession)ConnectionPools[SiteId];
            return null;
        }


        private void NewConnection(int key, WebSocketSession session)
        {
            lock (ConnectionPools)
            {
                if (ConnectionPools.ContainsKey(key))
                    ConnectionPools[key] = session;
                else
                {
                    ConnectionPools.Add(key, session);
                    onFirstConnection(key);
                }
            }
        }

        private void ParseAndInitNewConnection(String msg, WebSocketSession aConnection)
        {
            String[] _datas = msg.Split(new char[] { ' ' });

            if (_datas.Length > 1)
            {
                var _cmd = _datas[0].Trim();
                var _param = _datas[1].Trim();
                int _sypId = -1;

                if (_cmd.Equals("NEW") && Int32.TryParse(_param, out _sypId))
                {
                    NewConnection(_sypId, aConnection);

                    _Output("New connection for site : " + _sypId, Output.OUT);
                    _Output("check-synchronise " + _sypId, Output.OUT);
                    _Output("check-synchronise "+_sypId, Output.COMMAND);
                }
                else
                {
                    _Output(msg.Trim(), Output.OUT);
                    _Output(msg.Trim(), Output.COMMAND);
                }
            }
            else
                _Output(msg.Trim(), Output.COMMAND);
        }

        private bool Setup(Action<ServerConfig> configurator)
        {
            var rootConfig = new RootConfig { DisablePerformanceDataCollector = true };

            var config = new ServerConfig();
            configurator(config);

            return SypWebSocketServer.Setup(rootConfig, config, null, null, new ConsoleLogFactory(), null, null);
        }


        public void Start(int cpt)
        {
           // IPAddress ipAddress = Dns.Resolve("localhost").AddressList[0];
            if (SypWebSocketServer.Start())
                _Output("WebSocket server successfully started, try[" + cpt + "]", Output.OUT);
            else
            {
                if (cpt <= autoRestartLoop)
                {
                    SypWebSocketServer.Stop();
                    Start(cpt + 1);
                    _Output("WebSocket server failed to start, try[" + cpt + "]", Output.ERROR);
                }
                else
                    _Output("WebSocket server failed to start at last try", Output.ERROR);
            }
        }

        public void SendAll(string msg)
        {
            lock (ConnectionPools)
            {
                foreach (WebSocketSession _ws in ConnectionPools.Values)
                {
                    if (_ws != null)
                        _ws.Send(msg);
                }
            }
        }

        public void SendMessage(int SiteId, string msg)
        {
            lock (ConnectionPools)
            {
                WebSocketSession _ws = GetWebSocketSession(SiteId);
                if (_ws != null)
                    _ws.Send(msg);
                else
                    _Output("Failed to send following data to site " + SiteId + " : " + msg, Output.ERROR);
            }
        }


        public void Kick(int SiteId)
        {
            lock (ConnectionPools)
            {
                WebSocketSession _ws = GetWebSocketSession(SiteId);
                if (_ws != null)
                    _ws.Close(CloseReason.ServerClosing);
            }

        }

        public void Stop()
        {
            SypWebSocketServer.Stop();
        }

        public SypWebsocketSuperPoolServer(SetText Ouput)
        {
            _Output = Ouput;
            SypWebSocketServer = new WebSocketServer();

            this.Setup(c =>
              {
                  c.Name = "Syp WebSocket Server";
                  c.Port = SypGarbageConf.Instance().SypServerPort;
                  c.Ip = "Any";
                  c.MaxConnectionNumber = 100;
              });

            SypWebSocketServer.NewSessionConnected += new SessionHandler<WebSocketSession>(SypWebSocketServer_NewSessionConnected);
            SypWebSocketServer.NewMessageReceived += new SessionHandler<WebSocketSession, string>(SypWebSocketServer_NewMessageReceived);
            SypWebSocketServer.SessionClosed += new SessionHandler<WebSocketSession, CloseReason>(SypWebSocketServer_SessionClosed);

            if (ConnectionPools == null)
            {
                ConnectionPools = new Hashtable();
            }
        }

        #region Events

        private void SypWebSocketServer_NewSessionConnected(WebSocketSession ws)
        {
            
        }

        private void SypWebSocketServer_NewMessageReceived(WebSocketSession ws, string msg)
        {
            ParseAndInitNewConnection(msg, ws);
        }

        private void SypWebSocketServer_SessionClosed(WebSocketSession ws, CloseReason reason)
        {
            lock (ConnectionPools)
            {
                foreach (int _key in ConnectionPools.Keys)
                {
                    if (ConnectionPools[_key] != null)
                    {
                        WebSocketSession _ws = (WebSocketSession)ConnectionPools[_key];
                        if (_ws.Equals(ws))
                        {
                            _Output("WebSocket connection " + _key + " closed", Output.OUT);
                            return;
                        }
                    }
                }
            }
        }

        #endregion
    }
}
